//
//  classify.cc
//  test_facetracker
//
//  Created by Jennifer Wong on 5/8/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#ifndef __classify_h_
#define __classify_h_

#include <iostream>
#include <vector>
#include <fstream>
#include <math.h>

using namespace std;

std::vector<std::vector<double> > feature_vectors;

std::string classify(std::vector<double> test_vector, std::string training_filename) {
    std::ifstream training_set_file;
    training_set_file.open(training_filename.c_str());
    std::string line;
    
    std::vector<std::vector<double> > training_vectors;
    std::vector<std::string> names;
    
    // Parses text file, and generates corresponding feature_vectors
    while (training_set_file.good()) {
        getline(training_set_file,line);
        if (line.size() == 0) continue;
        char *cptr = new char[line.size()];
        std::strncpy(cptr, line.c_str(), line.size());
        
        char * pch;
        pch = std::strtok(cptr, ": ");
        names.push_back(std::string(pch));
        
        std::vector<double> single_vector;
        pch = std::strtok(NULL, ": ");
        while (pch != NULL) {
            single_vector.push_back(atof(std::string(pch).c_str()));
            pch = std::strtok(NULL, ": ");
        }
        training_vectors.push_back(single_vector);

    }
    
    training_set_file.close();
    
    // Calculates the sums of squared differences for each feature vector
    std::vector<double> SSDs;
    for (int i = 0; i < training_vectors.size(); i++) {
      double SSD = 0;
      for (int j = 0; j < training_vectors[i].size(); j++) {
	SSD += pow((training_vectors[i][j] - test_vector[j]), 2);
      }
      std::cout << "\n score for " << names[i] << " = " << SSD << std::endl;
      SSDs.push_back(SSD);
    }
    
    // Classifies test_vector through NN
    std::vector<double>::iterator result;
    result = std::min_element(SSDs.begin(), SSDs.end());
    int minIndex = std::distance(SSDs.begin(), result);
    std::string result_vector_id = names[minIndex];
     
    
    if (SSDs[minIndex] > 0.5)
      return "unknown user";

    return result_vector_id;
    
}

bool classifyIDSpecific(std::vector<double> test_vector, std::string training_filename,
                     std::string userID, double threshold) {
    std::ifstream training_set_file;
    training_set_file.open(training_filename.c_str());
    std::string line;
    
    std::vector<std::vector<double> > training_vectors;
    std::vector<std::string> names;
    
    
    // Parses text file, and generates corresponding feature_vectors
    while (training_set_file.good()) {
        getline(training_set_file,line);
        if (line.size() == 0) continue;
        char *cptr = new char[line.size()];
        std::strncpy(cptr, line.c_str(), line.size());
        
        char * pch;
        pch = std::strtok(cptr, ": ");
        names.push_back(std::string(pch));
        
        std::vector<double> single_vector;
        pch = std::strtok(NULL, ": ");
        while (pch != NULL) {
            single_vector.push_back(atof(std::string(pch).c_str()));
            pch = std::strtok(NULL, ": ");
        }
        training_vectors.push_back(single_vector);
        
    }
    
    training_set_file.close();
    
    // Calculates the sums of squared differences for each feature vector labeled with userID
    std::vector<double> IDSpecificSSDs;
    
    for (int i = 0; i < training_vectors.size(); i++) {
        if (names[i] == userID) {
            double IDSpecificSSD = 0;
            for (int j = 0; j < training_vectors[i].size(); j++) {
                IDSpecificSSD += pow((training_vectors[i][j] - test_vector[j]), 2);
            }
	    cout << "\n Next match score for " << userID << " = " << IDSpecificSSD << endl;
            IDSpecificSSDs.push_back(IDSpecificSSD);
        }
    }
    
    if (IDSpecificSSDs.size() == 0) return false;
    
    // Classifies test_vector through NN
    std::vector<double>::iterator IDSpecificResult;
    IDSpecificResult = std::min_element(IDSpecificSSDs.begin(), IDSpecificSSDs.end());
    int IDSpecificMinIndex = std::distance(IDSpecificSSDs.begin(), IDSpecificResult);
    double min = IDSpecificSSDs[IDSpecificMinIndex]; 
    cout << "\n min score = " << min << endl; 
    if(min > threshold) 
      {
	return false;
      }
    return true;
    
}

#endif

